///////////////////////////////////////////////////////////////////////////////////////////
// 程序名称: C语言 坦克大战（联机版）                                                         //
// 编译环境: MinGW64 g++编译器 make指令命令行编译，EasyX_2023大暑版                            //
// 项目类型: 基于EasyX的图形化网络游戏                                                        //
// 作   者: xming-kaede <526817087@qq.com>                                               //
// 版 本 号: 1.0.0_alpha                                                                 //
// 编写时间: 2024.7.1 13:00                                                              //
// 最后修改: 2024.7.11 21:00                                                             //
/////////////////////////////////////////////////////////////////////////////////////////


#include <cstdio>
#include "UI.h"
#include "ui/element/Container.h"
#include "ui/element/Block.h"
#include "ui/element/Map.h"
#include <tinycthread.h>
#include <cstdlib>
#include <network.h>
#include <procedure.h>
/*
 * 注：关于游戏网络与帧的设计
 *    暂定为一秒30帧，每帧进行画面更新和炮弹等位置计算
 *    单独线程读取玩家操作，向服务器发送相应数据包，不受游戏帧影响
 *    发送数据包用独立线程，且不受游戏帧影响
 *    接受数据包也是独立线程，在收到服务器的数据包后置标志位表示有新的操作需要处理
 *    只有在收到服务器发来的数据包时才进行相应操作，如画面更新
 *    客户端能发出的数据包有：游戏开始，玩家位置与朝向更新，，玩家炮弹发射，炮弹位置更新（自己的炮弹自己算,服务器不需要区分哪个炮弹，服务器只需要知道每一帧每个玩家的位置和炮弹位置即可）
 *    服务器发回的数据包有：转发与发回客户端发来的数据包（表示同意该事件发生），玩家阵亡事件，游戏结束
 *    udp数据：<[playercount(1B)room_info(any length)]>
 *    房间中的数据：玩家加入，玩家退出，游戏开始，房间解散，<[]>
 *      玩家请求进服：<[00]>          s < p
 *      服务器已满: <[01]>           s > p
 *      给玩家指定id：<[1id(1B)]>     s > p
 *      玩家加入：<[2playerid(1B)]>  s > p
 *      玩家退出：<[3playerid(1B)]>  s<>p
 *      游戏开始：<(40)>            s <> p  //暂定，后面可能会指定地图 玩家发回是指示已做好开始准备
 *      房间解散：<(50)>             s > p
 *      游戏结束后返回房间：<(6id(1B))> s < p
 *      房间玩家列表包：<(7ids(1B对应一个玩家)>  s > p
 *    数据包格式：<([playerid(1B)eventid(1B)tick(8B),data])> 例如   3c 28 5b 31 31 30 30 30 30 30 30 30 36 2c 30 30 30 30 30 30 30 5d 29 3e
 *                                                                <  (  [ id eid                   tick  , 方向      x         y  ]  )  >
 *                                                         表示事件id为1(玩家位置更新)，玩家id为1，在tick=00000006时，方向为0(朝右)，位置为0,0
 *    eid1 玩家位置更新 data: 方向(1B)x(3B)y(3B)                                              s <> p
 *    eid2 炮弹位置更新 data： 炮弹id(4B)x(3B)y(3B)                                           s <> p
 *    eid3 玩家蓄力 data: 蓄力秒数(1B)                                                        s <> p
 *    eid4 产生炮弹 data: 炮弹id(4B)x(3B)y(3B)炮弹等级(1B) 每个玩家的炮弹id独立，即两个玩家可以有一样id的炮弹     s <> p
 *    eid5 炮弹掉血 data: 炮弹id(4B)剩余血量(1B) 为0时销毁                                       s > p
 *    eid6 玩家子弹数更新: 子弹数(1B)                                                          s <> p
 *    eid7 玩家血量更新: 血量(1B) 为0时阵亡                                                     s > p
 *    eid8 方块血量更新: 列数(2B)行数(2B)血量(1B) 为0时销毁                                                     s > p
 *    eid9 玩家命数更新: 命数(1B) 为0时失败                                                     s > p
 *    eid10 游戏结束: 胜者id(1B)                                                              s > p
 *    eid11 玩家掉线: 玩家id(1B)                                                              s > p
 *    玩家自己发射的炮弹的轨迹由玩家自己计算，服务器负责计算重叠，更新血量等
*/

int Tick = 0;

int KeyThread(void *args) {
	handleLocalKey();
	return 0;
}
//主线程：ticker处理ui等
//键盘线程：读取本地io，执行对应操作
//服务器线程：独立于游戏，进行数据处理 =》产生子线程与各个客户端通信
//客户端线程：监听服务器发来的数据
//找房间线程
#include <tool.h>
void SleepSelectUS(SOCKET s, long long usec)
{
    struct timeval tv;
    fd_set dummy;
    FD_ZERO(&dummy);
    FD_SET(s, &dummy);
    tv.tv_sec = usec / 1000000L;
    tv.tv_usec = usec % 1000000L;
    select(0, 0, 0, &dummy, &tv);
    DWORD err = GetLastError();
    if (err != 0)
        printf("Error : %d", err);
}
#include <timeapi.h>
int main(){
    timeBeginPeriod(2);
	system("chcp 65001");
    InitNetwork();
    InitUI();
    ShowInitUI();
	thrd_t keyHandler;
	thrd_create(&keyHandler,KeyThread,NULL);
	while(true) {
        long long startTime = TimeMilliSecond();
        //ThreadSleepFor(33);
		if(GameStarted) { // 如果游戏开始，则Tick开始增加
            TickExecuteServerPack();
			Tick ++;
            if (Tick % 500 == 0) {
                printf("Tick: %d\n",Tick);
            }
		}
        long long endTime = TimeMilliSecond();
        long long duration = endTime-startTime;
        if (duration > 30) {
            printf("客户端帧率不稳定！实时帧率为%lld 渲染此帧花了%lld ms\n",1000/duration,duration);
        } else {
            Sleep(30-duration);
        }
	}
	thrd_join(keyHandler,NULL);
    return 0;
}
int GetTick()
{
    return Tick;
}
void SetTick(int tick)
{
    Tick = tick;
}

//
//system("chcp 65001");
//initgraph(999,666);
////cleardevice();
//setbkcolor(WHITE);
//setlinecolor(BLACK);
//IMAGE img,ri;
////CrashCurrentUI();
//loadimage(&img,_T("res/btank0.png"));
//
//cleardevice();
////800 * 600的地图
////auto *ct = new Container(GAME_UI,33,33,833,633,5);
////ct->draw();
//putimage(20,20,&img);
//auto *g = new Block(GAME_UI,40,40,80,80,2, nullptr,0x77e558);
//auto *g2 = new Block(GAME_UI,80,40,120,80,2, nullptr,0x57d1e5);
//auto *g3 = new Block(GAME_UI,120,40,160,80,2, nullptr,0xcc6ee5);
//auto *g4 = new Block(GAME_UI,160,40,200,80,2, nullptr,0xff3b8d);
//auto *g5 = new Block(GAME_UI,200,40,240,80,2, nullptr,0x707070);
//g->draw();
//g2->draw();
//g3->draw();
//g4->draw();
//g5->draw();
//RecoverFont();
//setbkmode(TRANSPARENT);
//cleardevice();
//
//m.loadFromFile("map/1.txt");
//m.draw();
//printf("yi\n");
//thrd_t keyHandler;
//thrd_create(&keyHandler,KeyThread,NULL);
//while(true);